<!----
  表格组件-可以实现增、册、改、查的功能
-->

<template>
  <div>
    <el-skeleton :rows="20" :loading="loading" :animated="true">
      <template #default>
        <!---表格查询-->
        <com-crud-operation
          v-if="tableConfig.isFormShow"
          ref="refOperation"
          v-bind="operationConfig"
          @submit-form="submitForm"
        ></com-crud-operation>
        <!---表格按钮-->
        <com-crud-button-operation
          ref="refComButtonOperation"
          v-if="tableConfig.operation && tableConfig.operation.show"
          v-bind="tableConfig.operation"
          @on-operation-button="handleOperationButton"
          @on-operation-search="headleOperationSearch"
          @on-operation-refresh="headleOperationRefresh"
        ></com-crud-button-operation>
        <!--表格-->
        <el-table
          ref="refTable"
          class="el-table"
          :height="tableConfig.height"
          :width="tableConfig.width"
          v-bind="tableConfig"
          v-loading="loadingTable"
          @select="select"
          @select-all="selectAll"
          @cell-click="cellClick"
          @cell-dblclick="cellDblclick"
          @row-click="rowClick"
          @expand-change="expandChange"
        >
          <!---则显示多选框-->
          <el-table-column
            v-if="tableConfig.selectionRow"
            v-bind="tableConfig.selectionOptions"
            type="selection"
          />
          <!---显示该行的索引-->
          <el-table-column v-if="tableConfig.indexRow" type="index" v-bind="tableConfig.indexRow" />
          <!--设置一个可以展开的按钮-->
          <el-table-column v-if="tableConfig.expand" type="expand" v-bind="tableConfig.expand" />

          <!--表格数据-->
          <template v-for="(items, index) in tableConfig.columns" :key="index">
            <el-table-column v-if="items.type == 'img'" v-bind="items">
              <template #default="scope">
                <img :src="scope.row[items.prop]" class="img" :style="items.style" />
              </template>
            </el-table-column>

            <!--字典处理-->
            <el-table-column v-else-if="items.dictName" v-bind="items">
              <template #default="scope">
                <template v-if="tableConfig.tableEdit">
                  <div v-show="!scope.row.edit">
                    {{ getDictName(items.dictName, scope.row[items.prop]) }}
                  </div>
                  <el-select
                    v-model="scope.row[items.prop]"
                    v-show="scope.row.edit"
                    v-bind="items.components"
                  >
                    <el-option
                      v-for="item in getDictList(items.dictName)"
                      :key="item.value"
                      :label="item.label"
                      :value="item.value"
                    />
                  </el-select>
                </template>
                <template v-else>
                  {{ getDictName(items.dictName, scope.row[items.prop]) }}
                </template>
              </template>
            </el-table-column>

            <el-table-column v-else-if="items.showPopover" v-bind="items">
              <template #default="scope">
                <el-popover effect="light" trigger="hover" placement="top" width="auto">
                  <template #default>
                    <div>{{ scope.row[items.prop] }}</div>
                  </template>
                  <template #reference>
                    <el-tag> {{ scope.row[items.prop] }} </el-tag>
                  </template>
                </el-popover>
              </template>
            </el-table-column>

            <!---是否可编辑处理-->
            <el-table-column v-else v-bind="items">
              <template #default="scope">
                <template v-if="tableConfig.tableEdit">
                  <span v-show="!scope.row.edit">{{ scope.row[items.prop] }}</span>
                  <div v-show="scope.row.edit">
                    <!---编辑组件-->
                    <!--时间查插件-->
                    <el-date-picker
                      @blur="onEdit(scope)"
                      @keyup.enter="onEdit(scope)"
                      v-bind="items.components"
                      v-model="scope.row[items.prop]"
                      v-if="items.type === 'datePicker'"
                    />
                    <el-input
                      @blur="onEdit(scope)"
                      @keyup.enter="onEdit(scope)"
                      v-else
                      v-bind="scope.row.components"
                      v-model="scope.row[items.prop]"
                    />
                  </div>
                </template>
                <template v-else>
                  {{ scope.row[items.prop] }}
                </template>
              </template>
            </el-table-column>
          </template>

          <!--按钮-->
          <el-table-column
            v-if="tableConfig.rowHandle"
            v-bind="tableConfig.rowHandle.columns"
            :width="tableConfig.rowHandle.width"
          >
            <template #default="scope">
              <com-crud-row-handle
                v-if="scope"
                ref="refRowHandle"
                :items="scope"
                v-bind="tableConfig.rowHandle"
                @rowHandle="rowHandle"
              ></com-crud-row-handle>
            </template>
          </el-table-column>
        </el-table>

        <!---分页-->
        <com-crud-pagination
          ref="refPagination"
          v-if="tableConfig.pagination && tableConfig.pagination.show"
          v-bind="tableConfig.pagination"
          @current-change="handleCurrentChange"
          @size-change="handleSizeChange"
        ></com-crud-pagination>

        <!----------弹框----------->
        <!--编辑-->
        <com-crud-edit
          ref="refComedit"
          v-bind="fromConfig"
          @submit-form="submitForm"
        ></com-crud-edit>

        <!--上传-->
        <com-Upload ref="refComUpload" @onUpload="importRequst"></com-Upload>
      </template>
    </el-skeleton>
  </div>
</template>

<script lang="ts" setup>
import { reactive, toRefs, useAttrs, ref, onMounted } from 'vue'
import request from '@/utils/request'
import { ElMessageBox, ElMessage, ElLoading } from 'element-plus'
import useDictStore from '@/store/modules/dict'
const getDict = useDictStore().getDict
const refTable = ref()
const loading = ref(true)
const loadingTable = ref(true)
const refComedit = ref()
const attrs = useAttrs() as any
const refComUpload = ref()
const getRequestDefault = reactive({
  page: 1, //当前页
  pageSize: 10 //每页显示多少
})
// 上一次点击的索引
const lastClickIndex = ref(undefined)
// 上一次选择的方式 1：单选，2：多选，3：连选
let lastSelectStatus = 1
interface buttonType {
  value: string
  icon: string
  name: string
  show: boolean
  size: string
  type: string
}

interface listData {
  id: string
}

//头部表单查询显示
const operationConfigDefault = {
  title: '',
  spaceSize: 'default',
  expand: false,
  inline: true,
  layout: 'vertical',
  labelPosition: 'right', //'left' | 'right' | 'top'
  formData: [],
  showButton: true
}
//表格默认值处理
const tableConfigDefault = {
  getRequest: {
    url: '',
    method: 'GET',
    data: {},
    async: true,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    transformParams: (args: object) => {}
  },
  selectionRow: {},
  selectionOptions: {},
  isFormShow: true,
  operation: {
    show: true
  },
  pagination: {
    show: true
  },
  indexRow: {},
  width: '100%',
  height: '420px',
  rowHandle: {
    width: '100%',
    columns: []
  },
  columns: [{}],
  headerCellStyle: {
    color: '#444',
    backgroundColor: '#CCDDFF'
  }
}

//表单修改
const fromConfigDefault = {}

/***
 * 对像设置层级在第一层，这样使用解构的时候才好使用默认值。
 */
const defaultSettings = reactive({
  tableConfig: {
    ...tableConfigDefault,
    ...attrs.tableConfig
  },
  fromConfig: {
    ...fromConfigDefault,
    ...attrs.fromConfig
  },
  operationConfig: {
    ...operationConfigDefault,
    ...attrs.operationConfig
  }
})
const { fromConfig, tableConfig, operationConfig } = toRefs(defaultSettings)
const selectionTable = ref(<any>[])
const selectionTableRow = ref({})
/**
 * 点击表格操作按钮的处理
 * @param itmes 按钮数据
 * @param scope  表格行的数据
 */
const rowHandle = (itmes: buttonType, scope: any) => {
  const { row } = scope
  if (fromConfig.value.operationConfig.formData.length) {
    fromConfig.value.operationConfig.formData.forEach((item: any) => {
      if (row && row[item.prop]) item.value = row[item.prop]
      if (!item.component) item.component = {}
      if (itmes.value === 'look') item.component.readonly = true
    })
  }
  let index = scope.$index
  switch (itmes.value) {
    case 'edit': //
      if (tableConfig.value.rowHandle.edit && tableConfig.value.rowHandle[itmes.value].handler) {
        tableConfig.value.rowHandle[itmes.value].handler(itmes, scope)
      } else {
        refComedit.value.show('update')
      }

      break
    case 'del': //删除
      tableConfig.value.data.splice(index, 1)
      if (tableConfig.value.rowHandle.del && tableConfig.value.rowHandle[itmes.value].handler) {
        tableConfig.value.rowHandle[itmes.value].handler(itmes, scope)
      }
      break
    case 'look': //查看
      if (tableConfig.value.rowHandle.look && tableConfig.value.rowHandle[itmes.value].handler) {
        tableConfig.value.rowHandle[itmes.value].handler(itmes, scope)
      } else {
        refComedit.value.show('look')
      }
      break
    default:
      if (
        tableConfig.value.rowHandle &&
        tableConfig.value.rowHandle.on &&
        tableConfig.value.rowHandle.on.handler
      ) {
        tableConfig.value.rowHandle.on.handler(itmes, scope) //自定义处理
      }
  }
}

//当前第几页
const handleCurrentChange = (page: Number) => {
  tableConfig.value.getRequest.data.page = page
  tableConfig.value.pagination.currentPage = page
  setTableData()
}
//每页显示多个条
const handleSizeChange = (pageSize: Number) => {
  tableConfig.value.getRequest.data.pageSize = pageSize
  tableConfig.value.pagination.pageSize = pageSize
  setTableData()
}

/**
 * 点击表格顶部按钮处理编辑、删除、导入、导出、打印等
 * @param items
 */
const handleOperationButton = (items: buttonType) => {
  switch (items.value) {
    case 'edit':
      if (tableConfig.value.operation.edit && tableConfig.value.operation[items.value].handler) {
        tableConfig.value.operation[items.value].handler(items)
      } else {
        refComedit.value.show('add')
      }
      break
    case 'del':
      if (tableConfig.value.operation.del && tableConfig.value.operation[items.value].handler) {
        tableConfig.value.operation[items.value].handler(items)
      } else {
        if (selectionTable.value.length) {
          onElMessageBox()
        } else {
          ElMessage({
            type: 'warning',
            message: '请选择需要删除的数据~~'
          })
        }
      }
      break
    case 'upload':
      if (tableConfig.value.operation.upload && tableConfig.value.operation[items.value].handler) {
        tableConfig.value.operation[items.value].handler(items)
      } else {
        onUpload()
      }
      break
    case 'download':
      if (
        tableConfig.value.operation.download &&
        tableConfig.value.operation[items.value].handler
      ) {
        tableConfig.value.operation[items.value].handler(items)
      } else {
        onDownload()
      }
      break
    default:
      if (
        tableConfig.value.operation &&
        tableConfig.value.operation.on &&
        tableConfig.value.operation.on.handler
      ) {
        tableConfig.value.operation.on.handler(items) //自定义处理
      }
  }
}

//删除提示
const onElMessageBox = () => {
  ElMessageBox.confirm('确定删除选择的数据吗?', '系统提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
    draggable: true
  })
    .then(() => {
      if (selectionTable.value.length) {
        let ids: string[] = []
        selectionTable.value.forEach((itme: listData) => {
          console.log(itme)
          ids.push(itme.id)
        })
        deleteRequest({ ids: ids.join() }).then((res: any) => {
          if (res) selectDelete()
        })
      }
    })
    .catch(() => {
      // ElMessage({
      //   type: 'info',
      //   message: 'Delete canceled'
      // })
    })
}

/**
 * 选择数据删除
 */
const selectDelete = (): void => {
  if (selectionTable.value.length) {
    selectionTable.value.forEach((itme: object) => {
      const index = tableConfig.value.data.findIndex((res: object) => res === itme)
      tableConfig.value.data.splice(index, 1)
    })
    ElMessage({
      type: 'success',
      message: '删除成功!'
    })
  }
}

/**
 * 表单提交处理
 * @param items
 * @param mode
 */
const submitForm = (items: Object, mode: string): void => {
  if (mode === 'query') onQuery(items)
  if (mode === 'add') onAdd(items)
  if (mode === 'update') onUpate(items)
}

/**
 * 查询-搜索
 * @param items
 */
const onQuery = (items: Object): void => {
  tableConfig.value.getRequest.data.page = 1
  tableConfig.value.getRequest.data = { ...tableConfig.value.getRequest.data, ...items }
  tableConfig.value.pagination.currentPage = 1
  setTableData()
}

/**
 * 添加
 * @param items
 */
const onAdd = (items: Object) => {
  addRequest(items).then((res: any) => {
    if (res) {
      tableConfig.value.pagination.currentPage = 1
      setTableData()
    }
  })
}
//
/**
 * 更新-编辑
 * @param items
 */
const onUpate = (items: Object) => {
  updateRequest(items).then((res: any) => {
    if (res) {
      setTableData()
    }
  })
}

//点击是否显查询内容
const headleOperationSearch = () => {
  tableConfig.value.isFormShow = !tableConfig.value.isFormShow
}

//点击搜索
const headleOperationRefresh = () => {
  if (tableConfig.value!.getRequest && tableConfig.value!.getRequest.url) {
    setTableData()
  }
}

/**
 * 获取数据
 */
const getRequest = () => {
  loadingTable.value = true
  let params = { ...getRequestDefault, ...tableConfig.value.getRequest.data }
  let promise = new Promise<void>((resolve, reject) => {
    request({
      url: tableConfig.value.getRequest.url,
      method: tableConfig.value.getRequest.method || 'get',
      params: params
    })
      .then(async (res) => {
        if (res) {
          if (tableConfig.value.getRequest.transformParams) {
            let resultData = tableConfig.value.getRequest.transformParams(res.data)
            resolve(resultData)
          } else {
            resolve(res.data)
          }
        }
      })
      .catch((error) => {
        reject(error)
      })
  })
  return promise
}

/**
 * 添加数据
 * @param items
 */
const addRequest = (items: object) => {
  let params = { ...tableConfig.value.addRequest.data, ...items }
  let promise = new Promise<void>((resolve, reject) => {
    request({
      url: tableConfig.value.addRequest.url,
      method: tableConfig.value.addRequest.method || 'POST',
      params: params
    })
      .then(async (res) => {
        if (res) {
          if (tableConfig.value.addRequest.transformParams) {
            let resultData = tableConfig.value.addRequest.transformParams(res.data)
            resolve(resultData)
          } else {
            resolve(res.data)
          }
        }
      })
      .catch((error) => {
        reject(error)
      })
  })
  return promise
}

/**
 * 更新编辑-数据
 * @param items
 */
const updateRequest = (items: object) => {
  let params = { ...tableConfig.value.updateRequest.data, ...items }
  let promise = new Promise<void>((resolve, reject) => {
    request({
      url: tableConfig.value.updateRequest.url,
      method: tableConfig.value.updateRequest.method || 'POST',
      params: params
    })
      .then(async (res) => {
        if (res) {
          if (tableConfig.value.updateRequest.transformParams) {
            let resultData = tableConfig.value.updateRequest.transformParams(res.data)
            resolve(resultData)
          } else {
            resolve(res.data)
          }
        }
      })
      .catch((error) => {
        reject(error)
      })
  })
  return promise
}

/**
 * 导出数据
 * @param items
 */
const exportRequest = () => {
  let params = { ...getRequestDefault, ...tableConfig.value.exportReust.data }
  let promise = new Promise<void>((resolve, reject) => {
    request({
      url: tableConfig.value.exportReust.url,
      method: tableConfig.value.exportReust.method || 'get',
      params: params
    })
      .then(async (res) => {
        if (res) {
          if (tableConfig.value.exportReust.transformParams) {
            let resultData = tableConfig.value.exportReust.transformParams(res.data)
            resolve(resultData)
          } else {
            resolve(res.data)
          }
        }
      })
      .catch((error) => {
        reject(error)
      })
  })
  return promise
}

/**
 * 导入
 * @param items
 */
const importRequst = (file: object) => {
  let params = { ...tableConfig.value.importRequst.data, ...file }
  let promise = new Promise<void>((resolve, reject) => {
    request({
      url: tableConfig.value.importRequst.url,
      method: tableConfig.value.importRequst.method || 'POST',
      params: params
    })
      .then(async (res) => {
        if (res) {
          if (tableConfig.value.importRequst.transformParams) {
            let resultData = tableConfig.value.importRequst.transformParams(res.data)
            resolve(resultData)
          } else {
            resolve(res.data)
          }
        }
      })
      .catch((error) => {
        reject(error)
      })
  })
  return promise
}

/**
 * 导出数据
 * @param items
 */
const deleteRequest = (items: object) => {
  let params = { ...tableConfig.value.deleteRequest.data, ...items }
  let promise = new Promise<void>((resolve, reject) => {
    request({
      url: tableConfig.value.deleteRequest.url,
      method: tableConfig.value.deleteRequest.method || 'POST',
      params: params
    })
      .then(async (res) => {
        if (res) {
          if (tableConfig.value.deleteRequest.transformParams) {
            let resultData = tableConfig.value.deleteRequest.transformParams(res.data)
            resolve(resultData)
          } else {
            resolve(res.data)
          }
        }
      })
      .catch((error) => {
        reject(error)
      })
  })
  return promise
}

//设置表格数据
const setTableData = () => {
  getRequest().then((res) => {
    tableConfig.value.data = res
    loading.value = false
    loadingTable.value = false
  })
}

/***
 * 下载数据-导出数据
 */
const onDownload = () => {
  const loading = ElLoading.service({
    lock: true,
    text: '正在下载中~~',
    background: 'rgba(0, 0, 0, 0.7)'
  })
  exportRequest().then((res: any) => {
    if (res) {
      setTimeout(() => {
        loading.close()
      }, 2000)
    }
  })
}

/**
 * 导入数据
 */
const onUpload = () => {
  refComUpload.value.show()
}

/******************表格点击数据的处理***************************** */

/**
 * 当用户手动勾选数据行的 Checkbox 时触发的事件
 * @param selection
 * @param row
 */
const select = (selection: [], row: object) => {
  selectionTable.value = selection
  selectionTableRow.value = row
}

//当用户手动勾选全选 Checkbox 时触发的事件
const selectAll = (selection: []) => {
  selectionTable.value = selection
}

//当某个单元格被点击时会触发该事件
const cellClick = (row: any) => {
  //selectionTable.value = Array.push(row)
}
//当某个单元格被双击击时会触发该事件
const cellDblclick = (row: any, column: object) => {
  tableConfig.value.data.forEach((item: any) => {
    if (item.id == row.id) {
      item.edit = !item.edit
    }
  })
}

//当某一行被点击时会触发该事件
//实现表格点击某一行选中，按ctrl点击行多选，按shift点击行连选
const rowClick = (row: any, column: object, e: any) => {
  // selectionTable.value = selectionTable.value.push(row)
  // 测试自定义禁用规则，如果这一行通过规则校验为false，说明这一行是禁止选择的，不进行勾选
  if (
    tableConfig.value.selectionOptions.selectableFn &&
    tableConfig.value.selectionOptions.selectableFn &&
    !tableConfig.value.selectionOptions.selectableFn(row)
  ) {
    return
  }
  const { ctrlKey, shiftKey } = e
  const rowIndex = tableConfig.value.data.findIndex((item: any) => item.id === row.id)
  if (!ctrlKey && !shiftKey) {
    // ctrl和shift都没有按下时单选
    // 如果上次的索引和这次的索引不同 或 上一次不是单选 则清空选择
    if (lastClickIndex.value !== rowIndex || lastSelectStatus !== 1) {
      refTable.value.clearSelection()
    }
    refTable.value.toggleRowSelection(row, undefined)
    lastSelectStatus = 1
  } else if (ctrlKey) {
    // 按下ctrl多选
    refTable.value.toggleRowSelection(row, undefined)
    lastSelectStatus = 2
  } else if (shiftKey) {
    // 按下shift连选
    if (lastClickIndex.value === undefined) {
      return
    }
    let minIndex: Number = 0
    let maxIndex: Number = 0
    if (rowIndex < lastClickIndex.value) {
      minIndex = rowIndex
      maxIndex = lastClickIndex.value + 1
    } else {
      minIndex = lastClickIndex.value
      maxIndex = rowIndex + 1
    }
    tableConfig.value.data
      .slice(minIndex, maxIndex)
      .forEach((item: any) => refTable.value.toggleRowSelection(item, true))
    lastSelectStatus = 3
  }
  lastClickIndex.value = rowIndex
}

//编辑更新单条
const onEdit = (scope: any) => {
  let { row } = scope
  updateRequest(row)
}

//当用户对某一行展开或者关闭的时候会触发该事件（展开行时，回调的第二个参数为 expandedRows；树形表格时第二参数为 expanded）
const expandChange = () => {}

//获取字典数据
const getDictName = (dictName: string, value: number | string) => {
  let dictData = getDict(dictName)
  if (dictData) {
    let res = dictData.find((itme) => itme.value == value)
    if (res && res.name) return res.name || res.label
  }
}

//获取字典数据
const getDictList = (dictName: string) => {
  return getDict(dictName)
}

//获取表格数据
onMounted(() => {
  if (tableConfig.value.getRequest && tableConfig.value.getRequest.async) {
    setTableData()
  }
})
</script>

<style lang="scss" scoped>
.el-table {
  width: 100%;
  .warning-row {
    --el-table-tr-bg-color: var(--el-color-warning-light-9);
  }
  .success-row {
    --el-table-tr-bg-color: var(--el-color-success-light-9);
  }
  .el-table__cell .el-button {
    margin-bottom: 10px;
    margin-left: 0;
    margin-right: 10px;
  }
  .img {
    width: 60px;
    height: 60px;
    margin: 0 auto;
    border-radius: 50%;
  }
}
</style>
